package com.ap.core.storedprocedure.impl;


import com.ap.core.common.tuple.ThreeTuple;
import com.ap.core.common.types.ParameterType;
import com.ap.core.storedprocedure.api.BaseStoredProcedure;
import com.ap.core.storedprocedure.api.StoredProcedureInfo;
import com.ap.core.storedprocedure.api.StoredProcedureResultInfo;
import org.hibernate.Session;
import org.hibernate.jdbc.Work;

import javax.persistence.EntityManager;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;


/**
 * Utility class for updating using stored procedures.
 */
public class UpdateProcedure extends BaseStoredProcedure {

    /**
     * Initialises the call string and in parameters.
     *
     * @param storedProcedureInfo Stored procedure info.
     */
    public UpdateProcedure(StoredProcedureInfo storedProcedureInfo) {
        super(storedProcedureInfo);
    }


    /**
     * Executes the update procedure using the entity manager.
     *
     * @param entityManager Entity manager to use.
     * @return Number records updated.
     */
    public int executeUpdate(EntityManager entityManager) {
        final Session session = (Session) entityManager.getDelegate();
        final StoredProcedureResultInfo storedProcedureResultInfo = new StoredProcedureResultInfo();
        session.doWork(new Work() {
            @Override
            public void execute(Connection connection) throws SQLException {
                CallableStatement cs = null;
                try {
                    cs = connection.prepareCall(storedProcedureInfo.getCallString());
                    int index = 0;
                    for (ThreeTuple<Integer, ?, ParameterType> inParam : storedProcedureInfo.getInParams()) {
                        if (ParameterType.IN == inParam.third) {
                            cs.setObject(++index, inParam.second, inParam.first);
                        } else {
                            cs.registerOutParameter(++index, inParam.first);
                        }
                    }
                    storedProcedureResultInfo.setUpdatedRecords(cs.executeUpdate());
                } catch (SQLException e) {
                    throw new RuntimeException("Error executing stored procedure " + storedProcedureInfo.getCallString(), e);
                } finally {
                    closeResources(cs, null);
                }
            }
        });

        return storedProcedureResultInfo.getUpdatedRecords();
    }


}
